package com.demo.flowable;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.FormService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.form.api.FormInfo;
import org.flowable.form.api.FormModel;
import org.flowable.form.model.FormField;
import org.flowable.form.model.SimpleFormModel;
import org.flowable.image.impl.DefaultProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author K
 */
@Slf4j
@Component
public class FlowableService {

    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource(name = "formServiceBean")
    private FormService formService;
    @Resource
    private RepositoryService repositoryService;

    /**
     * 学生请假审批工作流
     */
    public ProcessInstance leaveApproval(String teacherApproval) throws Exception {
        //流程定义的key,对应请假的流程图
        String processDefinitionKey = "leave_approval";
        //业务代码，根据自己的业务用
        String businessKey = "schoolleave";
        //流程变量，可以自定义扩充
        Map<String, Object> variablesDefinition = new HashMap<>(1);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey,
                businessKey, variablesDefinition);
        log.info("启动成功:{}", processInstance.getId());

        // 学生查询可以操作的任务,并完成任务
        List<Task> taskList =
                taskService.createTaskQuery().processInstanceId(processInstance.getId()).orderByTaskCreateTime().desc().list();
        for (Task task : taskList) {
            // 申领任务
            taskService.claim(task.getId(), "my");
            // 完成
            taskService.complete(task.getId());
        }

        // 生成流程图
        drawImg(processInstance, "请假审批.png");

        // 老师查询可以操作的任务,并完成任务
        // 候选组 xml文件里面的 flowable:candidateGroups="teacher"
        String candidateGroupTe = "teacher";
        List<Task> taskListTe = taskService.createTaskQuery().processInstanceId(processInstance.getId()).taskCandidateGroup(candidateGroupTe).orderByTaskCreateTime().desc().list();
        for (Task task : taskListTe) {
            // 申领任务
            taskService.claim(task.getId(), "teacher");
            // 完成
            Map<String, Object> variables = new HashMap<>(1);
            //携带变量，用于网关流程的条件判定，这里的条件是同意
            variables.put("command",teacherApproval);
            taskService.complete(task.getId(), variables);
        }

        // 校长查询可以操作的任务,并完成任务
        //候选组 xml文件里面的 flowable:candidateGroups="headmaster"
        candidateGroupTe = "headmaster";
        taskListTe = taskService.createTaskQuery().processInstanceId(processInstance.getId()).taskCandidateGroup(candidateGroupTe).orderByTaskCreateTime().desc().list();
        for (Task task : taskListTe) {
            // 申领任务
            taskService.claim(task.getId(), "headmaster");
            // 完成
            Map<String, Object> variables = new HashMap<>(1);
            //携带变量，用于网关流程的条件判定，这里的条件是同意
            variables.put("command","agree");
            taskService.complete(task.getId(), variables);
        }

        return processInstance;
    }

    /**
     * 学生请假审批工作流
     * 通过填写表单数据，再由决策表判断请假天数是否通过
     * @param days 请假天数
     */
    public ProcessInstance leaveFormApproval(String days) throws Exception {
        ProcessInstance processInstance = startProcess("w", "schoolleave");

        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
        // 申领任务
        taskService.claim(task.getId(), "my");

        Map<String, String> properties = new HashMap<>(1);
        properties.put("days", days);

        FormInfo taskFormModel = taskService.getTaskFormModel(task.getId());
        log.info("form id : {}，task id : {}", taskFormModel.getId(), task.getId());
        // 提交表单，等同于调用taskService.complete
        formService.submitTaskFormData(task.getId(), properties);

        // 生成流程图
        drawImg(processInstance, "表单请假审批.png");

        teacherApproval(processInstance);

        return processInstance;
    }

    public List<FormField> getFlowForm() {
        ProcessInstance processInstance = startProcess("w", "schoolleave");
        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
        FormInfo taskFormModel = taskService.getTaskFormModel(task.getId());
        SimpleFormModel formModel = (SimpleFormModel) taskFormModel.getFormModel();
        return formModel.getFields();
    }

    /**
     * 学生请假审批工作流
     * 通过数据对象，再由决策表判断请假天数是否通过
     * @param days 请假天数
     */
    public ProcessInstance leaveDataObjectsApproval(Integer days)  {
        ProcessInstance processInstance = startProcess("business", "schoolleave");

        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
        // 申领任务
        taskService.claim(task.getId(), "my");
        Map<String, Object> variables = new HashMap<>(2);
        //携带变量，用于网关流程的条件判定，这里的条件是同意
        variables.put("name","超级撒亚人");
        variables.put("days",days);

        taskService.complete(task.getId(), variables);

        teacherApproval(processInstance);

        return processInstance;
    }

    private void teacherApproval(ProcessInstance processInstance) {
        String candidateGroupTe = "teacher";
        Task task =
                taskService.createTaskQuery().processInstanceId(processInstance.getId()).taskCandidateGroup(candidateGroupTe).singleResult();
        if (task == null) {
            log.info("不通过");
        } else {
            // 申领任务
            taskService.claim(task.getId(), "teacher");
            // 完成
            Map<String, Object> variables = new HashMap<>(1);
            //携带变量，用于网关流程的条件判定，这里的条件是同意
            variables.put("command","true");
            taskService.complete(task.getId(), variables);

            task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
            log.info("task = {}", task);
        }
    }

    /**
     * 申请退货，商家超时未处理
     * @param returnWay 退货方式，退货退款和仅退款
     * @param returnMoney 退款金额
     * @return 流程实例
     */
    public ProcessInstance returnOverTime(String returnWay, Integer returnMoney) {
        ProcessInstance processInstance = startProcess("return", "return");

        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
        // 申领任务
        taskService.claim(task.getId(), "my");

        Map<String, String> properties = new HashMap<>(1);
        properties.put("return", returnWay);
        properties.put("return_money", returnMoney.toString());

        FormInfo taskFormModel = taskService.getTaskFormModel(task.getId());
        log.info("form id : {}，task id : {}", taskFormModel.getId(), task.getId());
        // 提交表单，等同于调用taskService.complete
        formService.submitTaskFormData(task.getId(), properties);

        return processInstance;
    }

    /**
     * 启动实例
     * @param processDefinitionKey 流程定义的key,对应请假的流程图
     * @param businessKey 业务代码，根据自己的业务用
     * @return 返回实例
     */
    private ProcessInstance startProcess(String processDefinitionKey, String businessKey) {
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey);
        log.info("启动成功:{}", processInstance.getId());
        return processInstance;
    }

    /**
     * 获取动态流程图，在执行中节点高亮显示
     * @param processInstance 流程实例
     * @throws IOException 异常
     */
    private void drawImg(ProcessInstance processInstance, String fileName) throws Exception {
        List<String> activeActivityIds = runtimeService.getActiveActivityIds(processInstance.getId());

        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        DefaultProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator();
        // 绘制bpmnModel代表的流程的流程图
        // 设置字体，要不然中文不会显示
        InputStream inputStream = diagramGenerator.generateDiagram(bpmnModel, "png", activeActivityIds, Collections.emptyList(),
                "宋体","宋体","宋体",null, 1.00,false);
        FileOutputStream output = new FileOutputStream("C:/文档/" + fileName);
        IOUtils.copy(inputStream, output);
    }
}
